/*
 * Copyright (C) 2009 Kristopher T Babic
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of
 * the GNU General Public License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program;
 * if not, see <http://www.gnu.org/licenses>.
 */

package edu.idp.client;

import edu.idp.client.anim.AdvancedSprite;
import edu.idp.client.anim.AnimationParameter;
import edu.idp.client.anim.AnimationPath;
import edu.idp.client.anim.LinePath;
import edu.idp.client.anim.sequence.ImageSequence;
import edu.idp.client.anim.sequence.ModelSequence;
import edu.idp.client.anim.sequence.Sequence;
import edu.idp.client.event.AnimationEvent;
import edu.idp.client.event.AnimationPathEvent;
import edu.idp.client.interfaces.AnimationEventListener;
import edu.idp.client.interfaces.AnimationPathEventListener;
import edu.idp.client.interfaces.SpriteAnimator;

import javax.swing.*;
import java.applet.Applet;
import java.awt.*;
import java.net.URL;
import java.util.Vector;

//(Sequence)Class.forName(in.substring(26, in.length())).newInstance();
/**
 *
 * @author Kristopher T Babic
 */
public class AnimationPanel extends Panel implements AnimationPathEventListener {

    public static int EVENT_LOCATION = 0;
    public static int EVENT_CREATE = 1;
    public static int EVENT_CANCEL = 2;

    private static final int MAX_SEQ = 2;

    private Button cancelButton;
    private Button setPathButton;
    private Button setLocButton;
    private Button changeParamButton;
    private Button backButton;
    private Button nextButton;
    private Button createButton;

    private Frame myFrame;
    private Label posLabel;
    private Label posX, posY;
    private Label posLabelX = null;
    private Label posLabelY = null;
    private Label pathLabel = null;

    private TextArea spriteLabel = null;
    private TextArea posTextX;
    private TextArea posTextY;
    private TextArea pathText;
    private TextArea timeSpan;

    private AdvancedSprite demoSprite;
    private Sequence demoSequence;
    private Vector animationEventListeners = null;
    private boolean pathSet = false;
    private boolean setLoc = false;

    private Point initLocation = null;

    private String sequenceName = null;
    private AnimationParameter sequenceParams = null;
    private Sequence selectedSequence = null;
    private AnimationPath animationPath = null;

    private Frame pathFrame = null;
    private Applet myApp = null;
    private SpritePanel spritePanel = null;

    private Sequence[] sequenceSelection = new Sequence[MAX_SEQ];
    private AnimationParameter[] sequenceParameters = new AnimationParameter[MAX_SEQ];
    private int selectedSequencePos = -1;

    public AnimationPanel(AnimationEventListener ael, Frame f, Applet ap) {
        super();

        this.myApp = ap;
        setLayout(null);
        setSize(500, 290);
        this.setBackground(new Color(12632256));

        setLocButton = new Button("Set Position");
        setLocButton.setBounds(10, 15, 150, 30);
        setLocButton.setBackground(new Color(12632256));
        add(setLocButton);

        setPathButton = new Button("Set Path");
        setPathButton.setBounds(10, 55, 150, 30);
        setPathButton.setBackground(new Color(12632256));
        add(setPathButton);

        changeParamButton = new Button("Change Parameters");
        changeParamButton.setBounds(10, 95, 150, 30);
        changeParamButton.setBackground(new Color(12632256));
        changeParamButton.setEnabled(false);
        add(changeParamButton);

        createButton = new Button("Create Animation");
        createButton.setBounds(10, 135, 150, 30);
        createButton.setBackground(new Color(12632256));
        createButton.setEnabled(false);
        add(createButton);

        cancelButton = new Button("Cancel");
        cancelButton.setBounds(10, 175, 150, 30);
        cancelButton.setBackground(new Color(12632256));
        add(cancelButton);

        backButton = new Button("<");
        backButton.setBounds(354, 146, 20, 20);
        backButton.setBackground(new Color(12632256));
        add(backButton);

        nextButton = new Button(">");
        nextButton.setBounds(457, 146, 20, 20);
        nextButton.setBackground(new Color(12632256));
        add(nextButton);

        posLabel = new Label("Initial Position:");
        posLabel.setBounds(176, 15, 80, 20);
        add(posLabel);

        posX = new Label("X:");
        posX.setBounds(177, 43, 10, 10);
        add(posX);

        posY = new Label("Y:");
        posY.setBounds(238, 43, 10, 10);
        add(posY);

        posTextX = new TextArea("XXX", 1, 4, TextArea.SCROLLBARS_NONE);
        posTextX.setEditable(false);
        posTextX.setBounds(191, 40, 29, 20);
        posTextX.setBackground(new Color(12632256));
        add(posTextX);

        posTextY = new TextArea("XXX", 1, 4, TextArea.SCROLLBARS_NONE);
        posTextY.setEditable(false);
        posTextY.setBounds(252, 40, 29, 20);
        posTextY.setBackground(new Color(12632256));
        add(posTextY);

        pathLabel = new Label("Selected Path:");
        pathLabel.setBounds(177, 70, 100, 10);
        add(pathLabel);

        pathText = new TextArea("None Selected", 3, 30, TextArea.SCROLLBARS_NONE);
        pathText.setBounds(177, 91, 150, 70);
        pathText.setEditable(false);
        pathText.setBackground(new Color(12632256));
        add(pathText);

        Label l = new Label("Description:");
        l.setBounds(354, 170, 100, 15);
        add(l);

        spriteLabel = new TextArea("", 15, 2, TextArea.SCROLLBARS_NONE);
        spriteLabel.setBounds(354, 187, 123, 70);
        spriteLabel.setEditable(false);
        spriteLabel.setBackground(new Color(12632256));
        add(spriteLabel);

        Label l2 = new Label("Life Span (seconds):");
        l2.setBounds(177, 170, 130, 15);
        add(l2);

        timeSpan = new TextArea("infinity", 15, 2, TextArea.SCROLLBARS_NONE);
        timeSpan.setBounds(177, 190, 100, 30);
        add(timeSpan);

        SymAction lSymAction = new SymAction();
        setLocButton.addActionListener(lSymAction);
        setPathButton.addActionListener(lSymAction);
        changeParamButton.addActionListener(lSymAction);
        createButton.addActionListener(lSymAction);
        cancelButton.addActionListener(lSymAction);
        backButton.addActionListener(lSymAction);
        nextButton.addActionListener(lSymAction);

        spritePanel = new SpritePanel();
        spritePanel.setBounds(356, 17, 119, 119);
        spritePanel.setBackground(new Color(12632256));
        add(spritePanel);


        this.myFrame = f;
        addAnimationEventListener(ael);
        startSpriteDisplay();

        //start();

    }

    public void paint(Graphics g) {

        Dimension size = this.getSize();
        // draw left separator
        g.setColor(Color.darkGray);
        g.drawLine(167, 0, 167, (int) size.getHeight());
        g.setColor(Color.white);
        g.drawLine(168, 0, 168, (int) size.getHeight());
//		g.setColor(Color.darkGray);
//		g.drawLine(169, 0, 169, 233);

        // draw right separator
        g.setColor(Color.darkGray);
        g.drawLine(335, 0, 335, (int) size.getHeight());
        g.setColor(Color.white);
        g.drawLine(336, 0, 336, (int) size.getHeight());
//		g.setColor(Color.darkGray);
//		g.drawLine(325, 0, 352, 233);

        g.setColor(Color.black);
        g.drawLine(354, 15, 476, 15);
        g.drawLine(354, 15, 354, 137);

        g.setColor(Color.darkGray);
        g.drawLine(355, 16, 475, 16);
        g.drawLine(355, 16, 355, 137);

        g.setColor(Color.white);
        g.drawLine(476, 15, 476, 137);
        g.drawLine(475, 16, 475, 137);
        g.drawLine(355, 137, 476, 137);
        g.drawLine(356, 136, 476, 136);

        //g.drawRect(355, 25, 120, 120);

/*    g.setColor(Color.white);
    g.fillRect(356, 26, 119, 119);
*/        /*
		// x-pos box top/left
		g.setColor(Color.black);
		g.drawLine(191, 45, 220, 45);
		g.drawLine(191, 45, 191, 65);
		g.setColor(Color.darkGray);
		g.drawLine(192, 46, 219, 46);
		g.drawLine(192, 46, 192, 64);

		// y-pos box top/left
		g.drawLine(252, 45, 281, 45);
		g.drawLine(252, 45, 252, 65);
		g.setColor(Color.darkGray);
		g.drawLine(253, 46, 280, 46);
		g.drawLine(253, 46, 253, 64);

		// x-pos box bottom/right
		g.setColor(Color.white);
		g.drawLine(193, 65, 221, 65);
		g.drawLine(193, 64, 221, 64);
		g.drawLine(220, 46, 220, 65);
		g.drawLine(221, 45, 221, 65);

		// x-pos box bottom/right
		g.drawLine(254, 65, 282, 65);
		g.drawLine(254, 64, 282, 64);
		g.drawLine(281, 46, 281, 65);
		g.drawLine(282, 45, 282, 65);
		*/
    }


    public void moveNext() {
        if (!atLast()) {
//System.out.println("moved from "+getSequencePosition()+" to "+(getSequencePosition()+1));
            setSequencePosition(getSequencePosition() + 1);
            updateSprite();
        }
    }

    public void movePrevious() {
        if (!atFirst()) {
//System.out.println("moved from "+getSequencePosition()+" to "+(getSequencePosition()-1));
            setSequencePosition(getSequencePosition() - 1);
            updateSprite();
        }
    }

    public void moveFirst() {
        if (!atFirst()) {
//System.out.println("moved from "+getSequencePosition()+" to "+(0));

            setSequencePosition(0);
            updateSprite();
        }
    }

    public void moveLast() {
        if (!atLast()) {
//System.out.println("moved from "+getSequencePosition()+" to "+(MAX_SEQ-1));
            setSequencePosition(MAX_SEQ - 1);
            updateSprite();
        }
    }

    protected void updateSprite() {
        demoSprite.setNewSequence(getSelectedSequence());
        spriteLabel.setText(demoSprite.getSequence().toString());
    }

    public boolean atFirst() {
        return (getSequencePosition() == 0);
    }

    public boolean atLast() {
        return (getSequencePosition() == (MAX_SEQ - 1));
    }

    protected int getSequencePosition() {
        return this.selectedSequencePos;
    }

    protected void setSequencePosition(int pos) {
        this.selectedSequencePos = pos;
    }

    public String getSelectedSequenceName() {
        return sequenceSelection[getSequencePosition()].getClass().getName();
//  return sequenceName;
    }

    public AnimationParameter getSelectedSequenceParameters() {
        return sequenceParameters[getSequencePosition()];
//  return sequenceParams;
    }

    public Sequence getSelectedSequence() {
        return sequenceSelection[getSequencePosition()];//selectedSequence;
    }

    public void setSelectedSequence(String seqName, AnimationParameter params) {
        this.sequenceName = seqName;
        this.sequenceParams = params;
    }

    public void setAnimationPath(AnimationPath ap) {
        this.animationPath = ap;
    }

    public AnimationPath getAnimationPath() {
        return this.animationPath;
    }


    private void startSpriteDisplay() {
        demoSequence = null;// 2-29-00 testing ///  new ModelSequence(); // 1-25 this);

        int loc = 0;

//********************************************************

        edu.idp.client.model.Cube3D model = new edu.idp.client.model.Cube3D();
        sequenceSelection[loc] = new ModelSequence(model);
        sequenceParameters[loc] = new AnimationParameter();
        sequenceParameters[loc].addParameter(model, model.getClass().getSuperclass());

//*******************************************************
        URL base = myApp.getCodeBase();
        URL[] spinImages = new URL[19];
        String file;
        for (int i = 0; i < spinImages.length; ++i) {
            file = "gifs/spin";

            if (i < 10) file += "0" + i + ".gif";
            else file += i + ".gif";
            try {
                spinImages[i] = new URL(base.toString() + file); //tk.getImage(new URL(base.toString() + file));  //myApp.getImage(base, file);
            }
            catch (Exception e) {
            }
        }
        sequenceSelection[++loc] = new ImageSequence(this, spinImages);


        sequenceParameters[loc] = new AnimationParameter();
        sequenceParameters[loc].addParameter(this, this.getClass().getSuperclass().getSuperclass().getSuperclass());
        sequenceParameters[loc].addParameter(spinImages, spinImages.getClass());

//********************************************************


        java.awt.Rectangle animBound = spritePanel.getBounds();
        LinePath animPath = new LinePath(new Point(animBound.width / 2, animBound.height / 2), new Point(0, 0));// AnimationPath.LINE);
        setAnimationPath(null);

//    setSelectedSequence(demoSequence.getClass().getName(), ap);// 1-26 new AnimationParameter());


        demoSprite = new AdvancedSprite(spritePanel);//03-01-00 , demoSequence, animPath);   //this, demoSequence, animPath); // 1-30-00  new Point(355, 25));
        demoSprite.setPath(animPath);
        moveFirst();
//    demoSprite.setLocation(animBound.width/2, animBound.height/2);
//    demoSprite.setBounds(0, 0, animBound.width, animBound.height);
//    demoSprite.setBounds(356, 26, 119, 119);
//    this.add(demoSprite);
        spritePanel.setLayout(null);
        spritePanel.add(demoSprite);
//    updateSprite();
        spritePanel.start();
    }

    public void run() {
        spritePanel.add(demoSprite);
        spritePanel.start();
    }

    public void stop() {
        spritePanel.stop();
        demoSprite.kill();
    }

    public void remove() {
        stop();
        demoSprite.kill();
    }


    public synchronized void addAnimationEventListener(AnimationEventListener ael) {
        if (animationEventListeners == null)
            animationEventListeners = new Vector();
        animationEventListeners.addElement(ael);
    }

    public synchronized void removeAnimationEventListener(AnimationEventListener ael) {
        if (animationEventListeners != null)
            animationEventListeners.removeElement(ael);
    }

    protected void fireEvent(AnimationEvent ae) {
        if (animationEventListeners == null)
            return;
        Vector targets;
        synchronized (this) {
            targets = (Vector) animationEventListeners.clone();
        }

        for (int i = 0; i < targets.size(); i++) {
            AnimationEventListener target = (AnimationEventListener) targets.elementAt(i);
            target.handleAnimationEvent(ae);
        }

    }

    protected void enableCreate() {
//System.out.println(pathSet+" : "+setLoc);
        if (pathSet && setLoc)
            createButton.setEnabled(true);
    }

    public Point getLocation() {
        return this.initLocation;
    }

    public void setLocation(Point p) {
        myFrame.setEnabled(true);
        myFrame.toFront();

        posTextX.setText(Integer.toString(p.x));
        posTextY.setText(Integer.toString(p.y));

        initLocation = p;
        setLoc = true;

        this.enableCreate();

        //this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        //this.setEnabled(true);
    }


    public Point getPath() {
        return new Point(5, 2);
    }

    public void setPath() {
    }

    /**
     * *******************************************
     * AnimationPathEvent inteface implementation
     * ********************************************
     */
    public void handleAnimationPathEvent(AnimationPathEvent ape) {
        if (ape != null) {
            //System.out.println(ape);
            this.pathSet = true;
            //System.out.println("in AnimationPanel: "+ape.getAnimationPath());
            this.setAnimationPath(ape.getAnimationPath());
            pathText.setText(getAnimationPath().toString());
            this.enableCreate();
        }
        run();
        myFrame.setEnabled(true);
    }

    /**
     * ******************************************
     * SymAction implementation
     * *******************************************
     */
    class SymAction implements java.awt.event.ActionListener {

        public void actionPerformed(java.awt.event.ActionEvent event) {
            Object object = event.getSource();
            if (object == setLocButton)
                setLocButton_ActionPerformed(event);
            else if (object == setPathButton)
                setPathButton_ActionPerformed(event);
            else if (object == changeParamButton)
                changeParamButton_ActionPerformed(event);
            else if (object == cancelButton)
                cancelButton_ActionPerformed(event);
            else if (object == nextButton)
                nextButton_ActionPerformed(event);
            else if (object == backButton)
                backButton_ActionPerformed(event);
            else if (object == createButton)
                createButton_ActionPerformed(event);
        }

        private void setLocButton_ActionPerformed(java.awt.event.ActionEvent event) {
            //AnimationPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
            myFrame.toBack();
            myFrame.setEnabled(false);
            AnimationEvent ae = new AnimationEvent(AnimationPanel.this, AnimationPanel.EVENT_LOCATION);
            fireEvent(ae);
            //AnimationPanel.this.setEnabled(false);
        }

        private void setPathButton_ActionPerformed(java.awt.event.ActionEvent event) {

            AnimationPanel.this.pathFrame = new ClosableFrame("Path Selection Screen", false);

            String osName = System.getProperty("os.name");
            boolean solarisWorkaround = (osName != null && (osName.indexOf("Solaris") != -1 || osName.indexOf("Irix") != -1));

            int diff = 0;
            if (solarisWorkaround)
                diff = 15;

            AnimationPanel.this.pathFrame.setSize(420, 250 + diff);
            AnimationPathPanel app = new AnimationPathPanel();
            app.addAnimationPathEventListener(AnimationPanel.this);
            AnimationPanel.this.pathFrame.add(app);//new AnimationPathPanel(AnimationPanel.this));
            AnimationPanel.this.pathFrame.setResizable(false);

            AnimationPanel.this.myFrame.setEnabled(false);

//      AnimationPanel.this.stop();

            AnimationPanel.this.pathFrame.setVisible(true);
//      AnimationPanel.this.setPath = true;
//      AnimationPanel.this.enableCreate();
        }

        private void changeParamButton_ActionPerformed(java.awt.event.ActionEvent event) {
        }

        private void cancelButton_ActionPerformed(java.awt.event.ActionEvent event) {
            AnimationPanel.this.remove();
//      AnimationPanel.this.demoSprite.kill();
            AnimationEvent ae = new AnimationEvent(AnimationPanel.this, AnimationPanel.EVENT_CANCEL);
            fireEvent(ae);
            if (AnimationPanel.this.pathFrame != null) {
                try {
                    AnimationPanel.this.pathFrame.dispose();
                }
                catch (java.lang.Exception e) {
                }
            }
            myFrame.dispose();
        }

        private void createButton_ActionPerformed(java.awt.event.ActionEvent event) {

            AnimationEvent ae = new AnimationEvent(AnimationPanel.this, AnimationPanel.EVENT_CREATE);//, AnimationPanel.this.getPath(), ap);
            long ts = -1l;
            if (!timeSpan.getText().equals("") && timeSpan.getText().indexOf("infinity") == -1) {
                try {
                    ts = 1000l * Long.parseLong(timeSpan.getText());
                }
                catch (Exception e) {
                    javax.swing.JOptionPane.showMessageDialog(AnimationPanel.this, "You have entered an invalid number for the life span.\nPlease try again.", "Error", javax.swing.JOptionPane.ERROR_MESSAGE);
                    return;
                }
            }
            if (ts != -1l)
                ae.setLifeSpan(ts);

            ae.setSequenceName(AnimationPanel.this.getSelectedSequenceName());
            ae.setSequenceParameters(AnimationPanel.this.getSelectedSequenceParameters());

            AnimationPath ap = AnimationPanel.this.getAnimationPath();

            ap.setOrigin(AnimationPanel.this.getLocation());
//      ap.setStartLocation(AnimationPanel.this.getLocation());
            ap.reset();
            ae.setAnimationPath(ap);


            fireEvent(ae);

            AnimationPanel.this.remove();
//      AnimationPanel.this.demoSprite.kill();
            myFrame.dispose();

        }

        private void nextButton_ActionPerformed(java.awt.event.ActionEvent event) {
            AnimationPanel.this.moveNext();
        }

        private void backButton_ActionPerformed(java.awt.event.ActionEvent event) {
            AnimationPanel.this.movePrevious();
        }

    }

    class SpritePanel extends JPanel implements Runnable, SpriteAnimator {

        private Thread animationThread;
        private boolean running = false;

        public void stop() {
            running = false;
        }

        public boolean running() {
            return running;
        }

        public void start() {
            animationThread = new Thread(this);
            running = true;
            animationThread.start();
        }

        public void run() {
            while (running == true) {
                animateSprites();
                try {
                    Thread.currentThread().sleep(100);
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
            animationThread = null;
        }

        public Vector getSprites() {
            int ncomps = getComponentCount();
            Component comp;
            Vector vector = new Vector();

            for (int i = 0; i < ncomps; ++i) {
                if ((comp = getComponent(i)) instanceof AdvancedSprite)
                    vector.addElement(comp);
            }
            return vector;
        }

        protected void animateSprites() {
            int ncomps = getComponentCount();
            Component comp;

            for (int i = 0; i < ncomps; ++i)
                if ((comp = getComponent(i)) instanceof AdvancedSprite)
                    ((AdvancedSprite) comp).animate();
        }

        public void redrawToForeground(java.awt.Rectangle bounds) {
        }

        /**
         * **********************************
         * SpriteAnimator IMPLEMENTATION
         * ***********************************
         */

        public void paintComponents(java.awt.Rectangle clip, boolean update) {
            Graphics g = this.getGraphics();

            g.setClip(clip);
            super.paint(g);

            g.dispose();
        }

        public void paintComponent(java.awt.Component comp) {
            java.awt.Rectangle bounds = comp.getBounds();
            Graphics compGraphics;
            Graphics g = this.getGraphics();

            compGraphics = g.create(bounds.x, bounds.y,
                                    bounds.width, bounds.height);
            comp.paint(compGraphics);

            compGraphics.dispose();
            g.dispose();
        }

    }

}

/*
        setLayout(null);
        setSize(540, 330);
        topButton = new Button();
        topButton.setLabel("^ ^");
        topButton.setBounds(384, 12, 24, 24);
        topButton.setBackground(new Color(12632256));
        add(topButton);

		SymAction lSymAction = new SymAction();
		topButton.addActionListener(lSymAction);
		

	class SymAction implements java.awt.event.ActionListener
	{
		public void actionPerformed(java.awt.event.ActionEvent event)
		{
			Object object = event.getSource();
			if (object == topButton)


*/